{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# THE CHSH GAME\n",
    "\n",
    "We are going to use (a simplified version) of the CHSH game to 'test' whether IBM's quantum computers are really quantum "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\Acer\\.conda\\envs\\name_of_my_env\\lib\\site-packages\\numpy\\_distributor_init.py:30: UserWarning: loaded more than 1 DLL from .libs:\n",
      "C:\\Users\\Acer\\.conda\\envs\\name_of_my_env\\lib\\site-packages\\numpy\\.libs\\libopenblas.NOIJJG62EMASZI6NYURL6JBKM4EVBGM7.gfortran-win_amd64.dll\n",
      "C:\\Users\\Acer\\.conda\\envs\\name_of_my_env\\lib\\site-packages\\numpy\\.libs\\libopenblas.PYQHXLVVQ7VESDPUVUADXEVJOBGHJPAY.gfortran-win_amd64.dll\n",
      "  warnings.warn(\"loaded more than 1 DLL from .libs:\\n%s\" %\n"
     ]
    }
   ],
   "source": [
    "#%matplotlib inline\n",
    "\n",
    "from qiskit import *\n",
    "from qiskit.tools.monitor import *\n",
    "from qiskit.providers.ibmq import least_busy\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define a function that creates the circuit that simulates Alice's and Bob's behaviour in the CHSH game. Parameters a0 and a1 are the measurement angles used by Alice when she receives 0 and 1, respectively. For Bob, b0 and b1 play the same role. The default parameters are the ones that give the maximum violation of the corresponding Bell inequality (or, equivalently, the highest winning probability)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Function to create the circuits for the CHSH game\n",
    "\n",
    "def CHSH_circuit(x,y,a0=0,a1=np.pi/2,b0=np.pi/4,b1=-np.pi/4):\n",
    "    \n",
    "    #x: bit received by Alice\n",
    "    #y: bit received by Bob\n",
    "    #a0: measure angle used by Alice when she receives 0\n",
    "    #a1: measure angle used by Alice when she receives 1\n",
    "    #b0: measure angle used by Bob when he receives 0\n",
    "    #b1: measure angle used by Bob when he receives 1\n",
    "    \n",
    "    circ = QuantumCircuit(2,2) \n",
    "    \n",
    "    # First, we create a Bell pair\n",
    "    \n",
    "    circ.h(0)\n",
    "    circ.cx(0,1)\n",
    "\n",
    "    # Now, we apply rotations for Alice and Bob depending on the bits they have received\n",
    "    \n",
    "    if(x==0):\n",
    "        circ.ry(a0,0)\n",
    "    else:\n",
    "        circ.ry(a1,0)\n",
    "\n",
    "    if(y==0):\n",
    "        circ.ry(b0,1)\n",
    "    else:\n",
    "        circ.ry(b1,1)\n",
    "\n",
    "    # We measure\n",
    "        \n",
    "    circ.measure(range(2),range(2)) # Medimos\n",
    "\n",
    "    return circ\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We also define a function to compute the winning probability. Notice how we can create a batch of circuits and send them for execution all at the same time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def winning_probability(backend, shots = 8192, a0=0,a1=np.pi/2,b0=np.pi/4,b1=-np.pi/4):\n",
    "    total = 0\n",
    "    circuits = [CHSH_circuit(0,0,a0,a1,b0,b1), CHSH_circuit(0,1,a0,a1,b0,b1), CHSH_circuit(1,0,a0,a1,b0,b1), CHSH_circuit(1,1,a0,a1,b0,b1)] # We 'pack' four different circuits for execution\n",
    "    job = execute(circuits, backend=backend, shots = shots)\n",
    "    # For the first three circuits, the winning condition is that Alice's and Bob's outputs are equal\n",
    "    for qc in circuits[0:3]:\n",
    "        counts = job.result().get_counts(qc)\n",
    "        if('00' in counts):\n",
    "            total += counts['00']\n",
    "        if('11' in counts):\n",
    "            total += counts['11']\n",
    "    # For the fourth circuit, Alice's and Bob's outputs must be different for them to win\n",
    "    counts = job.result().get_counts(circuits[3])\n",
    "    if('01' in counts):\n",
    "        total += counts['01']\n",
    "    if('10' in counts):\n",
    "        total += counts['10']\n",
    "        \n",
    "    return total/(4*shots)    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we try it on the simulator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.853424072265625\n"
     ]
    }
   ],
   "source": [
    "# Backend definition \n",
    "\n",
    "backend = Aer.get_backend('qasm_simulator')\n",
    "\n",
    "# Execution\n",
    "\n",
    "print(winning_probability(backend))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now run on an actual quantum computer. Is Nature classical or quantum? Let's find out! "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'IBMQ' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-1-7700c2a7a55f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# Load the account\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mprovider\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mIBMQ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mload_account\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;31m# We execute on the least busy device (among the actual quantum computers)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'IBMQ' is not defined"
     ]
    }
   ],
   "source": [
    "# Load the account\n",
    "\n",
    "provider = IBMQ.load_account()\n",
    "\n",
    "# We execute on the least busy device (among the actual quantum computers)\n",
    "\n",
    "backend = least_busy(provider.backends(operational = True, simulator=False, status_msg='active',\n",
    "                                       filters=lambda x: x.configuration().n_qubits > 1)) \n",
    "print(\"We are executing on...\",backend)\n",
    "\n",
    "print(winning_probability(backend))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
